package com.github.luoshu.open.shiro.redis;

import com.github.luoshu.open.shiro.ObjectUtils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author inme
 */
public class RedisTemplateManager implements RedisManager {
    private RedisTemplate<String , Object> redisTemplate;

    public RedisTemplateManager(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void putHash(String key, Map<Object, Object> data) {
        if(data == null || data.size() == 0){
            return;
        }
        for (Map.Entry<Object, Object> entry : data.entrySet()) {
            putHash(key , entry.getKey() , entry.getValue());
        }
    }

    @Override
    public void putHash(String key, Object hashKey, Object hashValue) {
        if(StringUtils.isEmpty(key)){
            throw new NullPointerException("key is null");
        }
        if(StringUtils.isEmpty(hashKey)){
            throw new NullPointerException("hashKey is null");
        }

        if(!(hashValue instanceof Serializable)){
            throw new RuntimeException(hashValue.getClass().getName() + " not impl Serializable");
        }

        byte[] keyBytes = ObjectUtils.serialize(hashKey);
        byte[] valueBytes = ObjectUtils.serialize(hashValue);


        HashOperations<String, byte[], byte[]> hash = this.redisTemplate.opsForHash();
        hash.put(key , keyBytes , valueBytes);
    }

    @Override
    public <T> T getHash(String key, Object hashKey) {
        byte[] keyBytes = ObjectUtils.serialize(hashKey);
        HashOperations<String, byte[], byte[]> hash = redisTemplate.opsForHash();
        byte[] bytes = hash.get(key, keyBytes);
        Object obj = ObjectUtils.deserialize(bytes);

        return (T) obj;
    }

    @Override
    public void deleteKey(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public Set<Object> getHashKeys(String key) {
        HashOperations<String, byte[], byte[]> hash = redisTemplate.opsForHash();

        Set<byte[]> keysBytes = hash.keys(key);
        if(keysBytes == null || keysBytes.size() == 0){
            return null;
        }

        Set<Object> keys = new HashSet<>();
        for (byte[] keysByte : keysBytes) {
            keys.add(ObjectUtils.deserialize(keysByte));
        }
        return keys;
    }

    @Override
    public void expire(String key, long expireMs) {
        redisTemplate.expire(key , expireMs , TimeUnit.MILLISECONDS);
    }

    @Override
    public void deleteHash(String key, Object hashKey) {
        redisTemplate.opsForHash().delete(key , hashKey);
    }

    @Override
    public boolean hasKey(String key) {
        Boolean hasKey = redisTemplate.hasKey(key);
        if(hasKey == null){
            hasKey = false;
        }
        return hasKey;
    }
}
